package com.xiao.mall.message.service;

import com.xiao.mall.foundation.service.CurdService;
import com.xiao.mall.foundation.service.SpecificationBuilder;
import com.xiao.mall.foundation.service.filter.StringFilter;
import com.xiao.mall.foundation.utils.UserAuthUtil;
import com.xiao.mall.message.domain.Notification;
import com.xiao.mall.message.rabbitmq.repository.NotificationRepository;
import com.xiao.mall.message.rabbitmq.repository.UserNotificationRepository;
import com.xiao.mall.message.service.dto.UserNotificationDto;
import com.xiao.mall.message.service.dto.front.NotificationFrontDto;
import com.xiao.mall.message.service.dto.front.UserNotificationFrontDto;
import com.xiao.mall.message.service.dto.front.UserNotificationTopicFrontDto;
import com.xiao.mall.message.service.mapper.UserNotificationMapper;
import com.xiao.mall.message.domain.UserNotification;
import com.xiao.mall.message.domain.enums.NotificationTopic;
//import com.xiao.message.service.mapper.front.NotificationFrontMapper;
import com.xiao.mall.message.service.mapper.front.UserNotificationFrontMapper;
//import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Optional;

@Service
public class UserNotificationService extends CurdService<UserNotification, UserNotificationDto, Long> {

    private final UserNotificationRepository userNotificationRepository;
    private final NotificationRepository notificationRepository;
    private final UserNotificationFrontMapper userNotificationFrontMapper;
//    private final NotificationFrontMapper notificationFrontMapper;
    private final SpecificationBuilder builder;
    @PersistenceContext
    private EntityManager entityManager;
  //  private final RabbitTemplate rabbitTemplate;

    protected UserNotificationService(UserNotificationRepository repository, UserNotificationMapper mapper,
                                      UserNotificationFrontMapper userNotificationFrontMapper,
//                                      NotificationFrontMapper notificationFrontMapper,
                                      //RabbitTemplate rabbitTemplate
                                      NotificationRepository notificationRepository) {
        super(repository, mapper);
        this.userNotificationRepository = repository;
        this.userNotificationFrontMapper = userNotificationFrontMapper;
//        this.notificationFrontMapper = notificationFrontMapper;
        //this.rabbitTemplate = rabbitTemplate;
        builder = new SpecificationBuilder();
        this.notificationRepository = notificationRepository;
    }

    @Transactional(readOnly = true)
    public List<UserNotificationFrontDto> findNotificationPageByUser(String type, String topic, Pageable pageable) {

        Long userId = UserAuthUtil.getCurrentUserId();
        StringFilter userFilter = new StringFilter();
        userFilter.setEquals(String.valueOf(userId));

//        Page<UserNotification> userNotificationPage = userNotificationRepository.findAll(SpecificationHelper.create(UserNotification.class)
//                .buildStringSpecification(userFilter, UserNotification_.userId)
//                .build()
//                .and(builder.equalsSpecification(notificationRoot -> notificationRoot.get("notification").get(Notification_.TYPE),
//                        NotificationType.valueOf(type)))
//                .and(builder.equalsSpecification(notificationRoot -> notificationRoot.get("notification").get(Notification_.TOPIC),
//                        NotificationTopic.valueOf(topic))), pageable);


//        return userNotificationPage.map(userNotificationFrontMapper::toDto).getContent();
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public NotificationFrontDto readMessage(Long notificationId) {
//        String userId = String.valueOf(UserAuthUtil.getCurrentUserId());
//        Optional<UserNotification> userNotificationOptional = userNotificationRepository.findByNotificationAndUserIdEqualsOrderByCreatedDateDesc(
//                Notification.builder().id(notificationId).build(), userId);
//        return userNotificationOptional.map(userNotification -> {
//            userNotification.setHasRead(true);
//            return notificationFrontMapper.toDto(userNotification.getNotification());
//        }).orElse(null);
        return null;
    }

    @Transactional(readOnly = true)
    public List<UserNotificationTopicFrontDto> findNotificationTopicGroupByUser(String type) {

        Long userId = UserAuthUtil.getCurrentUserId();

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<UserNotificationTopicFrontDto> cq = cb.createQuery(UserNotificationTopicFrontDto.class);
        Root<UserNotification> notificationRoot = cq.from(UserNotification.class);
//        cq.multiselect(notificationRoot.get("notification").get(Notification_.TOPIC).alias("topic"),
//                cb.max(notificationRoot.get("notification").get(Notification_.ID)).alias("maxId"),
//                cb.count(notificationRoot.get("notification").get(Notification_.ID)).alias("num"));
//        cq.where(cb.equal(notificationRoot.get(UserNotification_.userId), String.valueOf(userId)),
//                cb.equal(notificationRoot.get("notification").get(Notification_.TYPE), NotificationType.valueOf(type)),
//                cb.equal(notificationRoot.get(UserNotification_.HAS_READ), false));
//
//        cq.groupBy(notificationRoot.get("notification").get(Notification_.TOPIC));

        List<UserNotificationTopicFrontDto> userNotificationTopicFrontDtos = entityManager.createQuery(cq).getResultList();
        NotificationTopic.toList().forEach(topic -> {
            Optional<UserNotificationTopicFrontDto> userNotificationTopicFrontDtoOptional = userNotificationTopicFrontDtos.stream().filter(dto -> dto.getTopic().equals(topic)).findAny();
            //不存在
            if (!userNotificationTopicFrontDtoOptional.isPresent()) {
                UserNotificationTopicFrontDto dto = new UserNotificationTopicFrontDto();
                dto.setTopic(topic);
                dto.setNum(0L);
                userNotificationTopicFrontDtos.add(dto);
            } else {
                UserNotificationTopicFrontDto filterDto = userNotificationTopicFrontDtoOptional.get();
                Optional<Notification> notificationOptional = notificationRepository.findById(filterDto.getMaxId());
                notificationOptional.ifPresent(notification -> filterDto.setLatestContent(notification.getContent()));
            }
        });

        return userNotificationTopicFrontDtos;
    }

//    @Transactional(rollbackFor = Exception.class)
//    public void updateByUserIds(MergeUserTransactionDto dto) {
//        List<UserNotification> userNotifications = userNotificationRepository.findAllByUserId(dto.getOriginUserId().toString());
//
//        if (userNotifications.size() > 0) {
//            userNotificationRepository.updateByUserId(dto.getRevisedUserId().toString(), dto.getOriginUserId().toString());
//            Set<Long> ids = userNotifications.stream().map(UserNotification::getId).collect(Collectors.toSet());
//
//            dto.setClassName(UserNotification.class.getSimpleName());
//            dto.setOperationDate(LocalDateTime.now());
//            dto.setOperatorClassIds(ids.toString());
//            rabbitTemplate.convertAndSend(RabbitMqConstant.EXCHANGE_FANOUT_MERGE_USER_ACCOUNT, null, dto);
//        }
//    }
}